eletrotupi / tcc/ frontend/app/medicine-regimens/[id].tsxda87ae9932ae35c53b684fe28738b7ca50cbde17
7.1 KB | 234 lines Raw
1
import {
2
  View,
3
  StyleSheet,
4
  KeyboardAvoidingView,
5
  ScrollView,
6
  TouchableOpacity,
7
  ActivityIndicator,
8
} from "react-native";
9
import { Text } from "@/components/ui/Text";
10
import { useEffect, useState } from "react";
11
import { router, useLocalSearchParams } from "expo-router";
12
import { Card } from "@/components/ui/Cards";
13
import { Input } from "@/components/ui/Input";
14
import { Button } from "@/components/ui/Button";
15
import { Section, SectionHeader } from "@/components/ui/Sections";
16
import { Spacing, Typography, Colors, BorderRadius } from "@/constants/theme";
17
import { TimePicker } from "@/components/ui/TimePicker";
18
import { useMedicineRegimen, useUpdateMedicineRegimen } from "@/hooks";
19
import { MedicinePeriodicity } from "@/lib/api";
20

21
const PERIODICITY_OPTIONS: { label: string; value: MedicinePeriodicity }[] = [
22
  { label: "Uma vez", value: "ONCE" },
23
  { label: "Diário", value: "DAILY" },
24
  { label: "2x ao dia", value: "TWICE_DAILY" },
25
  { label: "3x ao dia", value: "THREE_TIMES_DAILY" },
26
  { label: "Semanal", value: "WEEKLY" },
27
  { label: "Quinzenal", value: "BIWEEKLY" },
28
  { label: "Mensal", value: "MONTHLY" },
29
];
30

31
function getTimePickerCount(p: MedicinePeriodicity): number {
32
  switch (p) {
33
    case "ONCE": return 0;
34
    case "DAILY": return 1;
35
    case "TWICE_DAILY": return 2;
36
    case "THREE_TIMES_DAILY": return 3;
37
    default: return 1;
38
  }
39
}
40

41
function timesToDates(times: string[]): Date[] {
42
  return times.map((t) => {
43
    const [h, m] = t.split(":").map(Number);
44
    const d = new Date();
45
    d.setHours(h, m, 0, 0);
46
    return d;
47
  });
48
}
49

50
export default function MedicineRegimenEdit() {
51
  const { id } = useLocalSearchParams<{ id: string }>();
52
  const { data, isLoading } = useMedicineRegimen(id);
53
  const updateRegimen = useUpdateMedicineRegimen();
54

55
  const [name, setName] = useState("");
56
  const [dosage, setDosage] = useState("");
57
  const [periodicity, setPeriodicity] = useState<MedicinePeriodicity>("DAILY");
58
  const [scheduledTimes, setScheduledTimes] = useState<Date[]>([]);
59
  const [initialized, setInitialized] = useState(false);
60

61
  useEffect(() => {
62
    if (data?.regimen && !initialized) {
63
      const r = data.regimen;
64
      setName(r.name);
65
      setDosage(r.dosage);
66
      setPeriodicity(r.periodicity as MedicinePeriodicity);
67
      setScheduledTimes(timesToDates(r.scheduledAt));
68
      setInitialized(true);
69
    }
70
  }, [data, initialized]);
71

72
  const handleSave = async () => {
73
    const count = getTimePickerCount(periodicity);
74
    const scheduledAt = scheduledTimes.slice(0, count).map(
75
      (d) =>
76
        `${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}`
77
    );
78

79
    await updateRegimen.mutateAsync({
80
      id,
81
      payload: { name, dosage, periodicity, scheduledAt },
82
    });
83
    router.back();
84
  };
85

86
  if (isLoading || !initialized) {
87
    return (
88
      <View style={styles.center}>
89
        <ActivityIndicator color={Colors.light.tint} />
90
      </View>
91
    );
92
  }
93

94
  return (
95
    <KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
96
      <ScrollView scrollEventThrottle={16}>
97
        <View style={styles.container}>
98
          <View style={styles.header}>
99
            <Text style={styles.headerTitle}>Editar medicamento</Text>
100
            <Text style={styles.headerSubtitle}>
101
              Atualize os detalhes do medicamento
102
            </Text>
103
          </View>
104

105
          <Section>
106
            <SectionHeader title="Detalhes" />
107
            <Card style={{ padding: Spacing.cardGap }}>
108
              <Input
109
                label="Nome"
110
                value={name}
111
                onChangeText={setName}
112
                placeholder="Ex: Fluoxetina"
113
                variant="darkGhost"
114
              />
115
              <Input
116
                label="Dosagem"
117
                value={dosage}
118
                onChangeText={setDosage}
119
                placeholder="Ex: 20mg"
120
                variant="darkGhost"
121
              />
122
            </Card>
123
          </Section>
124

125
          <Section>
126
            <SectionHeader title="Frequência" />
127
            <View style={styles.periodicityRow}>
128
              {PERIODICITY_OPTIONS.map((opt) => (
129
                <TouchableOpacity
130
                  key={opt.value}
131
                  style={[
132
                    styles.periodicityChip,
133
                    periodicity === opt.value && styles.periodicityChipActive,
134
                  ]}
135
                  onPress={() => {
136
                    setPeriodicity(opt.value);
137
                    const count = getTimePickerCount(opt.value);
138
                    setScheduledTimes((prev) =>
139
                      count === 0
140
                        ? []
141
                        : count > prev.length
142
                        ? [...prev, ...Array(count - prev.length).fill(new Date())]
143
                        : prev.slice(0, count)
144
                    );
145
                  }}
146
                  activeOpacity={0.7}
147
                >
148
                  <Text
149
                    style={[
150
                      styles.periodicityChipLabel,
151
                      periodicity === opt.value && styles.periodicityChipLabelActive,
152
                    ]}
153
                  >
154
                    {opt.label}
155
                  </Text>
156
                </TouchableOpacity>
157
              ))}
158
            </View>
159
          </Section>
160

161
          {scheduledTimes.length > 0 && (
162
            <Section>
163
              <SectionHeader
164
                title={scheduledTimes.length === 1 ? "Horário" : "Horários"}
165
              />
166
              {scheduledTimes.map((t, i) => (
167
                <View style={{ marginTop: 10 }} key={i}>
168
                  <TimePicker
169
                    value={t}
170
                    onChange={(date) =>
171
                      setScheduledTimes((prev) =>
172
                        prev.map((v, idx) => (idx === i ? date : v))
173
                      )
174
                    }
175
                  />
176
                </View>
177
              ))}
178
            </Section>
179
          )}
180

181
          <Button
182
            title="Salvar"
183
            onPress={handleSave}
184
            loading={updateRegimen.isPending}
185
            disabled={!name || !dosage}
186
          />
187
        </View>
188
      </ScrollView>
189
    </KeyboardAvoidingView>
190
  );
191
}
192

193
const styles = StyleSheet.create({
194
  keyboardView: { flex: 1 },
195
  center: { flex: 1, alignItems: "center", justifyContent: "center" },
196
  container: {
197
    gap: 24,
198
    paddingHorizontal: Spacing.containerPadding,
199
    paddingVertical: Spacing.sectionGap,
200
    marginBottom: 50,
201
  },
202
  header: { gap: 8 },
203
  headerTitle: { ...Typography.headlineMd },
204
  headerSubtitle: {
205
    ...Typography.bodyMd,
206
    color: Colors.light.textSecondary,
207
  },
208
  periodicityRow: {
209
    flexDirection: "row",
210
    flexWrap: "wrap",
211
    gap: 8,
212
  },
213
  periodicityChip: {
214
    paddingHorizontal: 16,
215
    paddingVertical: 10,
216
    borderRadius: BorderRadius.full,
217
    backgroundColor: "#fff",
218
    borderWidth: 1.5,
219
    borderColor: Colors.light.divider,
220
  },
221
  periodicityChipActive: {
222
    backgroundColor: Colors.light.tint + "1A",
223
    borderColor: Colors.light.tint,
224
  },
225
  periodicityChipLabel: {
226
    fontSize: 14,
227
    fontWeight: "500",
228
    color: Colors.light.text,
229
  },
230
  periodicityChipLabelActive: {
231
    fontWeight: "600",
232
    color: Colors.light.text,
233
  },
234
});